package cn.hum;

import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: huangzhibin
 * @Description:
 * @Date: Created in 2021-01-10
 * @Modified By:
 */
public class RpcRegister {
    //key：host， value : ClassName
    private static final Map<String, String> serviceMap = new HashMap<>();
    //key：host，value：port
    private static final Map<String, Integer> servicePortMap = new HashMap<>();

    public static void start(int host) {
        System.out.println("注册中心启动！！");
        try (ServerSocket serverSocket = new ServerSocket(host)) {
            while (true) {
                Socket client = serverSocket.accept();
                System.out.println("有服务进来.....");
                InetAddress inetAddress = client.getInetAddress();

                ObjectInputStream inputStream = new ObjectInputStream(client.getInputStream());
                ObjectOutputStream outputStream = new ObjectOutputStream(client.getOutputStream());
                String methodType = inputStream.readUTF();

                if (methodType.equals("register")) {
                    String serviceName = inputStream.readUTF();
                    int port = inputStream.readInt();
                    //注册类
                    serviceMap.put(inetAddress.getHostAddress(), serviceName);
                    //注册接口
                    servicePortMap.put(inetAddress.getHostAddress(), port);
                    System.out.println(String.format("有服务注册：host[%s] port[%d] class[%s]",
                            inetAddress.getHostAddress(), port, serviceName));

                    outputStream.writeBoolean(true);
                    outputStream.flush();

                } else if (methodType.equals("execute")) {
                    System.out.println("有服务调用.....");
                    //判断该类是否已经注册
                    String serviceHost = inputStream.readUTF();
                    String className = inputStream.readUTF();
                    boolean hasMethod = false;
                    if (serviceMap.containsKey(serviceHost) && serviceMap.get(serviceHost).equals(className)) {
                        hasMethod = true;
                    }
                    //返回消息给调用方
                    outputStream.writeBoolean(hasMethod);
                    outputStream.flush();

                    //存在该方法调用，转交给方法本身对象
                    String methodName = inputStream.readUTF();
                    Object paramsType = inputStream.readObject();
                    Object params = inputStream.readObject();
                    Object result = processRemote(className, methodName, paramsType, params,
                            new InetSocketAddress(serviceHost, servicePortMap.get(serviceHost)));

                    outputStream.writeObject(result);
                    outputStream.flush();
                }

                //关闭与客户端的连接
                client.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static Object processRemote(String className, String methodName, Object paramsTypes, Object params, InetSocketAddress remoteAddress) {
        ObjectOutputStream outputStream = null;
        ObjectInputStream inputStream = null;

        try (Socket socket = new Socket()) {
            socket.connect(remoteAddress);
            outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeUTF(className);
            outputStream.writeUTF(methodName);
            outputStream.writeObject(paramsTypes);
            outputStream.writeObject(params);
            outputStream.flush();

            //接收结果
            inputStream = new ObjectInputStream(socket.getInputStream());
            return inputStream.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (outputStream != null) outputStream.close();
                if (inputStream != null) inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}
